package cn.com.transfer.utils;

import org.xvolks.jnative.JNative;
import org.xvolks.jnative.Type;
import org.xvolks.jnative.exceptions.NativeException;
import org.xvolks.jnative.pointers.Pointer;
import org.xvolks.jnative.pointers.memory.MemoryBlockFactory;

import java.io.IOException;

/**
 * ICBC动态库调用
 */
public class IcbcNative {

    private static final String dll = "hsdes.dll";
    private static JNative WHGH_DES, GEN_MAC, HEX_2_DSP, DSP_2_HEX;

    static {
        try {
            WHGH_DES = new JNative(dll, "WHGH_DES");
            GEN_MAC = new JNative(dll, "GEN_MAC");
            HEX_2_DSP = new JNative(dll, "HEX_2_DSP");
            DSP_2_HEX = new JNative(dll, "DSP_2_HEX");
            //初始化密钥
            initKey();
        } catch (Exception e) {
            System.exit(0);
        }
    }

    //主密钥
    private static String mastKey;
    //交换密钥
    private static String exchKey;
    //pkg密钥
    private static String pkgKey;
    //mac密钥
    private static String macKey;

    public static void setPkgKey(String pkgKey) {
        IcbcNative.pkgKey = pkgKey;
    }

    public static void setMacKey(String macKey) {
        IcbcNative.macKey = macKey;
    }

    /**
     * 加密
     *
     * @param inBlock
     * @param type    0 交换密钥  其他 工作密钥
     * @return
     * @throws NativeException
     * @throws IllegalAccessException
     */
    public static String encrypt(String inBlock, Integer type) throws NativeException, IllegalAccessException {
        String sKey;
        if (type == 0) {
            sKey = exchKey;
        } else {
            sKey = pkgKey;
        }
        int len = inBlock.getBytes().length;
        byte[] en = desCode(0, mastKey, sKey, inBlock.getBytes(), len);
        return byte2Hex(en, len);
    }

    /**
     * 解密
     *
     * @param inBlock
     * @param type    0 交换密钥  其他 工作密钥
     * @return
     * @throws NativeException
     * @throws IllegalAccessException
     */
    public static String decrypt(String inBlock, Integer type) throws NativeException, IllegalAccessException {
        String sKey;
        if (type == 0) {
            sKey = exchKey;
        } else {
            sKey = pkgKey;
        }
        int len = inBlock.getBytes().length >> 1;
        byte[] bytes = hex2Byte(inBlock, len);
        bytes = desCode(1, mastKey, sKey, bytes, len);
        return new String(bytes);
    }

    /**
     * 生成mac
     *
     * @param dataIn
     * @param type   0 使用交换密钥   其他 使用工作密钥
     * @return
     * @throws NativeException
     * @throws IllegalAccessException
     */
    public static String getMac(String dataIn, Integer type) throws NativeException, IllegalAccessException {
        String sKey;
        if (type == 0) {
            sKey = exchKey;
        } else {
            sKey = macKey;
        }
        byte[] bytes = genMac(dataIn, mastKey, sKey);
        return byte2Hex(bytes, 4);
    }

    public static void dispose() throws IllegalAccessException, NativeException {
        WHGH_DES = null;
        GEN_MAC = null;
        HEX_2_DSP = null;
        DSP_2_HEX = null;
        System.gc();
    }

    /**
     * @param op      0加密 1 解密
     * @param mastKey 16位的主密钥
     * @param sKey     16位的工作密钥
     * @param inBlock 需要加解密的源数据
     * @return
     * @throws IllegalAccessException
     * @throws org.xvolks.jnative.exceptions.NativeException
     */
    private static byte[] desCode(int op, String mastKey, String sKey, byte[] inBlock, int len) throws IllegalAccessException, NativeException {
        WHGH_DES.setRetVal(Type.INT);
        int l = inBlock.length;
        if ((l & 0x07) != 0) {
            l = ((l >> 3) + 1) << 3;
        }

        Pointer data = new Pointer(MemoryBlockFactory.createMemoryBlock(l));
        Pointer in = new Pointer(MemoryBlockFactory.createMemoryBlock(inBlock.length));
        in.setMemory(inBlock);
        int i = 0;
        WHGH_DES.setParameter(i++, op);
        WHGH_DES.setParameter(i++, mastKey);
        WHGH_DES.setParameter(i++, sKey);
        WHGH_DES.setParameter(i++, in);
        WHGH_DES.setParameter(i++, data);
        WHGH_DES.setParameter(i++, len);
        WHGH_DES.invoke();

        byte[] bytes = data.getMemory();
        data.dispose();
        in.dispose();
        if (bytes != null && bytes.length != 0) {
            return bytes;
        } else {
            return null;
        }
    }

    /**
     * @param dataIn  需要校验的源数据
     * @param mastKey 16位的主密钥
     * @param sKey    16位的MAC密钥
     * @return
     * @throws IllegalAccessException
     * @throws org.xvolks.jnative.exceptions.NativeException
     */
    private static byte[] genMac(String dataIn, String mastKey, String sKey) throws IllegalAccessException, NativeException {
        GEN_MAC.setRetVal(Type.INT);
        Pointer data = new Pointer(MemoryBlockFactory.createMemoryBlock(4));
        int i = 0;
        GEN_MAC.setParameter(i++, dataIn.getBytes().length);
        GEN_MAC.setParameter(i++, dataIn);
        GEN_MAC.setParameter(i++, mastKey);
        GEN_MAC.setParameter(i++, sKey);
        GEN_MAC.setParameter(i++, data);
        GEN_MAC.invoke();

        byte[] bytes = data.getMemory();
        data.dispose();
        if (bytes != null && bytes.length != 0) {
            return bytes;
        } else {
            return null;
        }
    }

    /**
     * @param dsp
     * @param len
     * @return
     * @throws IllegalAccessException
     * @throws NativeException
     */
    private static String byte2Hex(byte[] dsp, int len) throws IllegalAccessException, NativeException {
        HEX_2_DSP.setRetVal(Type.INT);
        Pointer data = new Pointer(MemoryBlockFactory.createMemoryBlock(dsp.length * 2));
        Pointer in = new Pointer(MemoryBlockFactory.createMemoryBlock(dsp.length));
        in.setMemory(dsp);
        int i = 0;
        HEX_2_DSP.setParameter(i++, in);
        HEX_2_DSP.setParameter(i++, data);
        HEX_2_DSP.setParameter(i++, len);
        HEX_2_DSP.invoke();

        String str = data.getAsString();
        data.dispose();
        in.dispose();
        if (HEX_2_DSP.getRetValAsInt() == 0) {
            return str;
        } else {
            return null;
        }
    }

    /**
     * @param hex
     * @param len
     * @return
     * @throws IllegalAccessException
     * @throws NativeException
     */
    private static byte[] hex2Byte(String hex, int len) throws IllegalAccessException, NativeException {
        DSP_2_HEX.setRetVal(Type.INT);
        Pointer data = new Pointer(MemoryBlockFactory.createMemoryBlock(hex.length() >> 1));
        int i = 0;
        DSP_2_HEX.setParameter(i++, hex);
        DSP_2_HEX.setParameter(i++, data);
        DSP_2_HEX.setParameter(i++, len);
        DSP_2_HEX.invoke();

        byte[] bytes = data.getMemory();
        data.dispose();
        if (bytes != null && bytes.length != 0) {
            return bytes;
        } else {
            return null;
        }
    }

    /**
     * @throws IOException
     * @throws NativeException
     * @throws IllegalAccessException
     */
    private static void initKey() throws IOException, NativeException, IllegalAccessException {
        mastKey = "BB7E754B189667BA";
        exchKey = "20B7DAFB4CD6F90D";
        pkgKey = "5CE4233CD2177634";
        macKey = "2B1BCEC051CBA99C";

        /*String sKey = "HBICBC";
        byte[] bytes = new byte[32];
        InputStream is = IcbcNative.class.getClassLoader().getResourceAsStream("key");
        //mastkey密文(32)+exchkey密文(32)+pkgkey密文(32)+mackey密文(32)
        String key;
        List<String> keyList = new ArrayList();
        for (int i = 0; i < 4; i++) {
            is.read(bytes);
            byte[] keyBytes = hex2Byte(new String(bytes), 16);
            key = new String(desCode(1, sKey, sKey, keyBytes, 16));
            keyList.add(key);
        }
        int i = 0;
        mastKey = keyList.get(i++);
        exchKey = keyList.get(i++);
        pkgKey = keyList.get(i++);
        macKey = keyList.get(i++);
        is.close();*/
    }

}